#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdarg>
#include "include/Board.h"

using namespace std ;
using namespace BoardLib ;

#define debug


namespace SVGCont{
  
  template<typename T>
  class svgForArray{
  private:
    static const int INFOSIZE = 256 ;
    static const int ARRAYSIZE = 256 ;
    static const double UNITSIZE = 0.02 ;
    static const double HEIGHT = 0.025 ;
    char info_[INFOSIZE] ; // Store the info of current array;
    Board b ; 
    int c_ ; // count of actions performed on the array;
    double sx_, lx_, y_ ;
    int dim_ ; // dimension of arrays, just support 1 and 2 dimension array;
    int nx_, ny_ ; // length of each dimension of array;
    float fontsize_ ;
  protected:
    void printStep(){
      b.drawText( sx_, y_-UNITSIZE/2, "Step " ) ;
      sx_ += UNITSIZE ;
      char temp[1024] ;
      b.drawText( sx_, y_-UNITSIZE/2, itoa(c_, temp, 10) ) ;
      sx_ = 0.0 ;
      ++c_ ;
    }
    // note about buffer size
    void trans( char *val, double v ){
      sprintf( val, "%lf", v ) ;      
    }
    void trans( char *val, int v ){
      sprintf( val, "%d", v ) ;
    }
    void trans( char *val, const string &v ){
      strcpy( val, v.c_str() ) ;
    }
    void trans( char *val, long long v ){
      sprintf( val, "%lld", v ) ;
    }
    void trans( char *val, const char *v ){
      strcpy( val, v ) ;
    }
    void drawVal( const char *val ){
      b.setFontSize( 10 ) ;
      double x, y ;
      x = lx_+UNITSIZE/10 ;
      y = y_-HEIGHT/2 ;
      b.drawText( x, y, val ) ;
      b.setFontSize( fontsize_ ) ;
    }
    void drawUnit( double &x, double &y, const T &v, bool f = false ){
      if ( f ){
	b.setFillColorRGBi( 102, 0, 0 ) ;
	b.drawRectangle( x, y, UNITSIZE, UNITSIZE ) ;
	b.setFillColorRGBi( 255, 255, 255 ) ;
      }
      else
	b.drawRectangle( x, y, UNITSIZE, UNITSIZE ) ;
      //transform T and call drawVal ;
      char temp[INFOSIZE] ;
      trans( temp, v ) ;
      drawVal( temp ) ;
      x += UNITSIZE ;
    }
    void drawLine( double &x, double &y, int n, const T *arr, int px = -1 ){
      for ( int i = 0 ; i < n ; ++i ){
	if ( px == i )
	  drawUnit( x, y, arr[i], true ) ;
	else
	  drawUnit( x, y, arr[i] ) ;
      }
     
      y += HEIGHT ;
      x = 2*UNITSIZE ;
    }
    void drawLine( double &x, double &y, int n, int *arr, int an, const T *aval, bool f = false ){
      for ( int i = 0 ; i < n ; ++i ){
	bool f = false ;
	for ( int j = 0 ; j < an ; ++j )
	  if ( i == arr[j] ){
	    drawUnit( x, y, aval[i], true ) ;	  
	    f = true ;
	    break ;
	  }
	if ( !f )
	  drawUnit( x, y, aval[i] ) ;
      }
      if ( !f )
	y += HEIGHT ;
      else
	y += UNITSIZE ;
      x = 2*UNITSIZE ;
    }
    /*
    void drawMatrix( double &x, double &y, int dx, int dy, int px, int py, const T *arr ){
      for ( int i = 0 ; i < dx ; ++i ){
	if ( i == px )
	  drawLine( x, y, dy, arr, py ) ;
	else
	  drawLine( x, y, dy, arr ) ;
	//y += UNITSIZE ;
      }
    }
    */
    void drawMatrix( double &x, double &y, int dx, int dy, int *arr, int an, const T *varr ){
      int tarr[ARRAYSIZE][ARRAYSIZE] ;
      int len[ARRAYSIZE] ;
      for ( int i = 0 ; i < dx ; ++i ){
	int ptr = 0 ;
	for ( int j = 0 ; j < an ; j += 2 )
	  if ( arr[j] == i )
	    tarr[i][ptr++] = arr[j+1] ;
	len[i] = ptr ;
      } 
#ifdef debug1
      for ( int i = 0 ; i < dx ; ++i ){
	for ( int j = 0 ; j < dy ; ++j )
	  cout << varr[i][j] << " " ;
	cout << endl ;
      }
#endif

      for ( int i = 0 ; i < dx ; ++i )
	if ( i != dx-1 )
	  drawLine( x, y, dy, tarr[i], len[i], &varr[i], true ) ;
	else
	  drawLine( x, y, dy, tarr[i], len[i], &varr[i] ) ;
      return ;
    }
    void draw( double &x, double &y, int px = -1, int py = -1 ){ // draw array
      if ( dim_ == 1 )
	drawLine( x, y, nx_, px ) ;
      else
	drawMatrix( x, y, nx_, ny_, px, py  ) ;
    }
  public:
    svgForArray( const char * info, int nx, int ny = 0, int dim = 1 )  
      : c_(0), dim_(dim), nx_(nx), ny_(ny), fontsize_(11.0) {
      sx_ = y_ = 0.0 ;
      lx_ = 2*UNITSIZE ;
      strcpy( info_, info ) ;
    }
    void iniSVG( T const * arr ) { // draw the basic array ;
      //b.drawText( x_, y_, "Ini Array" ) ;
      //y_ += strlen( "Ini" ) ;
      //x_ += UNITSIZE ;
      printStep() ;
      //draw( x_, y_ ) ;\
      
      if ( dim_ == 1 ){
	drawLine( lx_, y_, nx_, 0, 0, arr ) ;
      }
      else { // dim_ == 2
	drawMatrix( lx_, y_, nx_, ny_, 0, 0, arr ) ;
      }
    }
    void resizeArray( int len, T const * arr ) { // if resize the array, re-draw svg
      nx_ = len ;
      iniSVG( arr ) ;
      return ;
    }
    /*
    void updateSVG( const T *arr, int px, int py = -1 ){
      printStep() ;
      if ( dim_ == 1 )
	draw( x_, y_, px ) ;
      else
	draw( x_, y_, px, py ) ;
    }
    */
    void updateSVG( const T *arr, int n, ... ){
      printStep() ;
      va_list vl ;
      va_start(vl, n) ;
      assert( n >= 0 ) ;
      int pos[n+1] ;
      for ( int i = 0 ; i < n ; ++i )
	pos[i] = va_arg( vl, int ) ;
      va_end(vl) ;

#ifdef debug
      for ( int i = 0 ; i < n ; ++i )
	cout << pos[i] << " " ;
#endif

      if ( dim_ == 1 ){
	drawLine( lx_, y_, nx_, pos, n, arr ) ;
      }
      else { // dim_ == 2
	drawMatrix( lx_, y_, nx_, ny_, pos, n, arr ) ;
      }
    }
    void writeSVG( const char *name ){
      b.saveSVG( name, 0.5 ) ;
    }
  } ;
}


int main( void ){
  SVGCont::svgForArray<int> t("test", 3) ;
  int arr[3] ;
  for ( int i = 0 ; i < 3 ; ++i )
    arr[i] = i ;
  t.iniSVG( arr ) ; // debug
  // operate on element 0, 1, 2 at this time
  arr[0] = 9 ; arr[1] = 10 ; arr[2] = 11 ;
  t.updateSVG( arr, 3, 0, 1, 2 ) ; // debug
  for ( int i = 0 ; i < 3 ; ++i )
    if ( i == 1 ){
      arr[i] = 100 ;
      t.updateSVG( arr, 1, i ) ;
    }
    else {
      arr[i] = 7 ;
      t.updateSVG( arr, 1, i ) ;
    }


  /*
  char temp[246] ;
  for ( int i = 0 ; i < 3 ; ++i ) {
    //for ( int j = 0 ; j < 3 ; ++j ){
      arr[i] = i
      cout << arr[i][j] << " " ;
      //}
      //cout << endl ;
  }
  t.iniSVG( &arr[0][0] ) ;
  t.updateSVG( &arr[0][0], 4, 0, 1, 2, 2 ) ;
  for ( int i = 0 ; i < 3 ; ++i ){
    if ( i == 1 ){
      arr[i][0] = 33 ;
      t.updateSVG( &arr[0][0], 2, i, 0 ) ;
    }
    else{
      arr[i][0] = 22 ;
      t.updateSVG( &arr[0][0], 2, i, 0 ) ;
    }
  }
  */
  t.writeSVG( "fordebug.svg" ) ;
  //test
  Board b ;
  b.drawRectangle(0, 0, 0.1, 0.1 ) ;
  b.drawRectangle(0, 0.2, 0.1, 0.1 ) ;
  b.saveSVG("test.svg") ;
  return 0 ;
}
